/*!
 * \file http_analysis.c
 *
 * \brief http/1.x analysis 函数
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 3.0
 * \author geyh
 * \date 2016/01/28
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "frmem.h"
#include "frsutl.h"

#include "frbyte_buffer.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "../comm/http_comm.h"
#include "../config.h"


#define FR_HTTP_LINE_END              "\r\n"
#define HTTP_HEADER_MAX_SIZE           1048576          /* 1M */

extern void *g_p_apm_context;


/*******************************************************************************
*  FUNC     :  取http请求头信息
*  ARGS     :  p_tcp_body           (指向体的头)
*           :  ui_tcp_body_len       (体的长度)
*  RTN      :  NULL                 (不是HTTP)
*           :  != NULL              (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC char * __http_req_header_detect(char *p_tcp_body, unsigned int ui_tcp_body_len, char **pp_uri
        , int *p_i_uri_len, int *p_i_option, Frreport_body_data *p_st_body_data)
{
    char *p_pos = NULL;
    unsigned int ui_left_len = ui_tcp_body_len;
    char *p_uri = NULL;
    unsigned int ui_method_len = 0, ui_uri_len = 0;
    int i_ret = 0;
    const char *p_field_value = NULL;

    if(p_tcp_body == NULL || ui_tcp_body_len == 0)
        return NULL;

    //取第一行(Request-Line)
    p_pos = strstr(p_tcp_body , FR_HTTP_LINE_END);
    if(p_pos)
    {
        ui_left_len = p_pos - p_tcp_body;
        if(ui_left_len == 0)
            return NULL;
    }
    else
        return NULL;

    //判断是否符合Request-Line格式(Method SP Request-URI SP HTTP-Version CRLF)
    //请求方法(Method)判断
    p_pos = strchr(p_tcp_body, ' ');
    if(p_pos == NULL)
        return NULL;

    ui_method_len = p_pos - p_tcp_body;

    switch (ui_method_len)
    {
        case 3:
            if(strncmp(p_tcp_body,"GET " , 4) == 0)
            {
                *p_i_option = 1;
                p_field_value = "GET";
            }
            else if(strncmp(p_tcp_body, "PUT " , 4) == 0)
                p_field_value = "PUT";
            else if(strncmp(p_tcp_body, "ACL " , 4) == 0)
                p_field_value = "ACL";

            break;

        case 4:
            if (strncmp(p_tcp_body,"POST ", 5) == 0 )
            {
                *p_i_option = 2;
                p_field_value = "POST";
            }
            else if (strncmp(p_tcp_body,"HEAD ", 5) == 0)
                p_field_value = "HEAD";
            else if(strncmp(p_tcp_body,"COPY ", 5) == 0)
                p_field_value = "COPY";
            else if(strncmp(p_tcp_body,"MOVE ", 5) == 0)
                p_field_value = "MOVE";
            else if(strncmp(p_tcp_body,"LOCK ", 5) == 0)
                p_field_value = "LOCK";
            else if(strncmp(p_tcp_body,"BIND ", 5) == 0)
                p_field_value = "BIND";
            else if(strncmp(p_tcp_body,"LINK ", 5) == 0)
                p_field_value = "LINK";

            break;

        case 5:
            if (strncmp(p_tcp_body,"TRACE ", 6) == 0)
                p_field_value = "TRACE";
            else if (strncmp(p_tcp_body,"PATCH ", 6) == 0)
                p_field_value = "PATCH";
            else if (strncmp(p_tcp_body,"MKCOL ", 6) == 0)
                p_field_value = "MKCOL";
            else if (strncmp(p_tcp_body,"LABEL ", 6) == 0)
                p_field_value = "LABEL";
            else if (strncmp(p_tcp_body,"MERGE ", 6) == 0)
                p_field_value = "MERGE";

            break;

        case 6:
            if(strncmp(p_tcp_body,"DELETE ", 7) == 0)
                p_field_value = "DELETE";
            else if(strncmp(p_tcp_body,"UNLOCK ", 7) == 0)
                p_field_value = "UNLOCK";
            else if(strncmp(p_tcp_body,"REBIND ", 7) == 0)
                p_field_value = "REBIND";
            else if(strncmp(p_tcp_body,"REPORT ", 7) == 0)
                p_field_value = "REPORT";
            else if(strncmp(p_tcp_body,"SEARCH ", 7) == 0)
                p_field_value = "SEARCH";
            else if(strncmp(p_tcp_body,"UNBIND ", 7) == 0)
                p_field_value = "UNBIND";
            else if(strncmp(p_tcp_body,"UNLINK ", 7) == 0)
                p_field_value = "UNLINK";
            else if(strncmp(p_tcp_body,"UPDATE ", 7) == 0)
                p_field_value = "UPDATE";

            break;

        case 7:
            if (strncmp(p_tcp_body,"OPTIONS ", 8) == 0)
                p_field_value = "OPTIONS";
            else if(strncmp(p_tcp_body,"CHECKIN ", 8) == 0)
                p_field_value = "CHECKIN";

            break;

        case 8:
            if (strncmp(p_tcp_body,"PROPFIND ", 9) == 0)
                p_field_value = "PROPFIND";
            else if(strncmp(p_tcp_body,"CHECKOUT ", 9) == 0)
                p_field_value = "CHECKOUT";

            break;

        case 9:
            if (strncmp(p_tcp_body,"PROPPATCH ", 10) == 0)
                p_field_value = "PROPPATCH";

            break;

        case 10:
            if (strncmp(p_tcp_body,"MKACTIVITY ", 11) == 0)
                p_field_value = "MKACTIVITY";
            else if (strncmp(p_tcp_body,"MKCALENDAR ", 11) == 0)
                p_field_value = "MKCALENDAR";
            else if (strncmp(p_tcp_body,"ORDERPATCH ", 11) == 0)
                p_field_value = "ORDERPATCH";
            else if (strncmp(p_tcp_body,"UNCHECKOUT ", 11) == 0)
                p_field_value = "UNCHECKOUT";

            break;

        case 11:
            if (strncmp(p_tcp_body,"MKWORKSPACE ", 12) == 0)
                p_field_value = "MKWORKSPACE";

            break;

        case 13:
            if (strncmp(p_tcp_body,"MKREDIRECTREF ", 14) == 0)
                p_field_value = "MKREDIRECTREF";

            break;

        case 15:
            if (strncmp(p_tcp_body,"VERSION-CONTROL ", 16) == 0)
                p_field_value = "VERSION-CONTROL";

            break;

        case 16:
            if (strncmp(p_tcp_body,"BASELINE-CONTROL ", 17) == 0)
                p_field_value = "BASELINE-CONTROL";

            break;

        case 17:
            if (strncmp(p_tcp_body,"UPDATEREDIRECTREF ", 18) == 0)
                p_field_value = "UPDATEREDIRECTREF";

            break;

        default:
            return NULL;

    }
    
    if(p_field_value == NULL)
        return NULL;

    if(p_st_body_data)
    {
        i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.method", p_field_value);
        if(i_ret == FR_FAIL)
            return NULL;
    }
    p_tcp_body += (ui_method_len + 1);
    ui_left_len -= (ui_method_len + 1);

    //取第2个space
    p_pos = (char *)memchr(p_tcp_body, ' ', ui_left_len);
    if(!p_pos)
        return NULL;

    //获取uri
    if(pp_uri)
    {
        ui_uri_len = p_pos - p_tcp_body + 1;
        p_uri = (char *)frmalloc(ui_uri_len);
        if(p_uri == NULL)
            return NULL;

        memcpy(p_uri, p_tcp_body, ui_uri_len - 1);
        p_uri[ui_uri_len - 1] = '\0';
        //设置出例参数
        *pp_uri = p_uri;
        *p_i_uri_len = ui_uri_len - 1;
    }

    ui_left_len -= p_pos - p_tcp_body + 1;
    p_tcp_body = p_pos + 1;
    //HTTP-Version格式判定(HTTP/1*DIGIT.1*DIGIT)
    if(strncmp(p_tcp_body, "HTTP/", 5) != 0)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }
    //跳过[HTTP/]
    p_tcp_body += 5;
    ui_left_len -= 5;

    p_pos = (char *)memchr(p_tcp_body, '.', ui_left_len);
    if(p_pos == NULL || p_pos == p_tcp_body)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }
    //判断第一个DIGIT
    for(; p_tcp_body < p_pos; p_tcp_body++)
    {
        if(*p_tcp_body < '0' || *p_tcp_body > '9')
        {
            if (pp_uri)
            {
                frfree(*pp_uri);
                *pp_uri = NULL;
            }
            return NULL;
        }
        else
        {
            ui_left_len--;
        }
    }

    //跳过[.]
    p_tcp_body += 1;
    ui_left_len -= 1;

    //判断第二个DIGIT
    if (ui_left_len == 0)
    {
        if (pp_uri)
        {
            frfree(*pp_uri);
            *pp_uri = NULL;
        }
        return NULL;
    }

    for(; ui_left_len; ui_left_len--)
    {
        if(*p_tcp_body < '0' || *p_tcp_body > '9')
        {
            if (pp_uri)
            {
                frfree(*pp_uri);
                *pp_uri = NULL;
            }
            return NULL;
        }
        p_tcp_body++;
    }

    p_tcp_body += 2;
    return p_tcp_body;
}

/*******************************************************************************
*  FUNC     :  取http请求头信息中的字段，存入链表当中
*  ARGS     :  p_header_tmp         (指向信息头)
*           :  p_i_header_tmp_len   (信息长度)
*  RTN      :  APM_L7_ANALYZE_FAIL                    (失败)
*           :  APM_L7_ANALYZE_TODO                    (数据包格式错误 执行丢包）
*           :  APM_L7_ANALYZE_SUCC                    (解析结束）
*  NOTE     :
*******************************************************************************/
FR_STATIC int __http_get_req_inf(L7session_http_private *p_st_private, Frbyte_Packet *p_packet
        , Frreport_body_data *p_st_body_data, char *p_uri
        , int i_uri_len, int *p_i_data_len , int i_option
        , int i_pos_start, int i_pos_end)
{
    char *p_value = NULL, *p_value_tmp1 = NULL, *p_value_tmp2 = NULL;
    char *p_field_name = NULL, *p_field_name_tmp = NULL;
    unsigned int ui_value_len = 0, ui_name_len = 0;
    int i_pos = 0, i_ret = 0;
    int i_pos_tmp = i_pos_start;
    char tmp;
    char *p_boundary = NULL;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_packet == NULL || p_st_body_data == NULL || p_uri == NULL
       || p_st_private == NULL || i_pos_start > i_pos_end || i_pos_start < 0)
        goto ERROR;

    if(p_st_private->i_version == 1)
    {
        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
    }
    else if(p_st_private->i_version == 2)
    {
        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
    }

    //循环取字段名跟值
    while(i_pos_tmp < i_pos_end - 4)
    {
        //获取字段名  格式错误
        if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, ":", 1, &i_pos) != FR_SUCC)
        {
            p_http1_session->i_flag_abandon = 1;
            p_http1_session->i_flag_req_finish = 1;
            return APM_L7_ANALYZE_FAIL;
        }

        //内存分配
        ui_name_len = (unsigned int)i_pos - i_pos_tmp;
        p_field_name = (char *)frmalloc(ui_name_len + 1);
        if(p_field_name == NULL)
            goto ERROR;
        //获取字段名
        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_name_len, p_field_name);
        if(i_ret == FR_FAIL)
            goto ERROR;
        p_field_name[ui_name_len] = '\0';
        frtrim(p_field_name);

        //转化为小写
        i_ret = frstrlower(p_field_name, ui_name_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            return APM_L7_ANALYZE_FAIL;
        }

        //指向：后一个字符
        i_pos_tmp = i_pos + 1;
        //获取value
        if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
            goto ERROR;

        ui_value_len = (unsigned int)i_pos - i_pos_tmp;
        p_value = (char *)frmalloc(ui_value_len + 1);
        if(p_value == NULL)
            goto ERROR;

        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_value_len, p_value);
        if(i_ret == FR_FAIL)
            goto ERROR;
        p_value[ui_value_len] = '\0';
        frtrim(p_value);
        //p_header_tmp指向下一行
        i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);
        //如果下一行空格开头则前移

        if(i_pos_tmp < i_pos_end)
        {
            bytebuffer_get_at(p_packet, i_pos_tmp, (uint8_t *)&tmp);
            while(tmp == ' ' || tmp == '\t')
            {
                //跳过空格
                i_pos_tmp++;
                if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
                    goto ERROR;

                ui_value_len = (unsigned int)i_pos - i_pos_tmp;
                p_value_tmp1 = (char *)frmalloc(ui_value_len + 1);
                if(p_value_tmp1 == NULL)
                    goto ERROR;
                i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_value_len, p_value_tmp1);
                if(i_ret == FR_FAIL)
                    goto ERROR;
                p_value_tmp1[ui_value_len] = '\0';
                frtrim(p_value_tmp1);
                //合并
                ui_value_len = strlen(p_value) + strlen(p_value_tmp1) + 1;
                p_value_tmp2 = (char *)frmalloc(ui_value_len);
                if(p_value_tmp2 == NULL)
                    goto ERROR;

                snprintf(p_value_tmp2, ui_value_len, "%s%s", p_value, p_value_tmp1);
                frfree(p_value);
                frfree(p_value_tmp1);
                p_value_tmp1 = NULL;
                p_value = p_value_tmp2;
                p_value_tmp2 = NULL;
                //p_header_tmp指向下一行
                i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);
                bytebuffer_get_at(p_packet, i_pos_tmp, (uint8_t *)&tmp);
            }

            frtrim(p_value);
        }


        //如果是content
        //请求体长度
        if(strcasecmp(p_field_name, "Content-Length") == 0)
        {
            *p_i_data_len = atoi(p_value);
        }
        else if(strcasecmp(p_field_name, "Content-Type") == 0)
        {
            //获取charset
            p_value_tmp1 = strstr(p_value, "charset=");
            if(p_value_tmp1 == NULL)
            {
                snprintf(p_comm_session->arr_charset, sizeof(p_comm_session->arr_charset), "%s", "utf-8");
            }
            else
            {
                //指向内容
                p_value_tmp1 += 8;
                snprintf(p_comm_session->arr_charset, sizeof(p_comm_session->arr_charset), "%s", p_value_tmp1);
                p_value_tmp1 = strchr(p_comm_session->arr_charset, ';');
                if(p_value_tmp1)
                    *p_value_tmp1 = '\0';

                frtrim(p_comm_session->arr_charset);
            }

            http_data_type_detect(p_value,p_comm_session);

            //p_boundary
            p_value_tmp1 = strstr(p_value, "boundary=");
            if(p_value_tmp1)
            {
                //boundary
                p_comm_session->i_flag_multipart = 1;

                //指向=之后 获取boundary
                p_value_tmp1 += 9;
                p_value_tmp2 = strchr(p_value_tmp1, ';');
                if(p_value_tmp2 == NULL)
                    ui_value_len = strlen (p_value_tmp1) + 1;
                else
                    ui_value_len = p_value_tmp2 - p_value_tmp1 + 1;

                p_boundary = (char *)frmalloc(ui_value_len);
                if(p_boundary == NULL)
                {
                    p_value_tmp1 = NULL;
                    p_value_tmp2 = NULL;
                    goto ERROR;
                }
                snprintf(p_boundary, ui_value_len, "%s", p_value_tmp1);
                p_value_tmp1 = NULL;
                p_value_tmp2 = NULL;

                if(p_comm_session->p_boundary)
                    frfree(p_comm_session->p_boundary);
                p_comm_session->p_boundary = p_boundary;
                p_boundary = NULL;

            }
        }
        else if(strcasecmp(p_field_name, "Host") == 0)//如果是host，则在末尾添加URL字段
        {
            p_value_tmp1 = strchr(p_value, ':');
            if(p_value_tmp1)
            {
                //把host后面的 ：置0
                *p_value_tmp1 = '\0';

                if(frreport_body_l7_add_str (p_st_body_data, "request.http.host", p_value) == FR_FAIL)
                {
                    p_value_tmp1 = NULL;
                    goto ERROR;
                }
                *p_value_tmp1 = ':';
            }
            else
            {
                if(frreport_body_l7_add_str (p_st_body_data, "request.http.host", p_value) == FR_FAIL)
                    goto ERROR;
            }


            //去掉uri中的空格
            frtrim(p_uri);
            //判断uri是否为完整的host
            if(strncasecmp(p_uri, "http://", 7) == 0 || strncasecmp(p_uri, "https://", 8) == 0)
            {
                frfree(p_value);
                p_value = NULL;
                p_value = frstrdup(p_uri);
                if(p_value == NULL)
                    goto ERROR;
            }
            else
            {
                //加"http://"
                if(strcasestr(p_value,"http://") == NULL)
                {
                    ui_value_len = strlen(p_value) + strlen("http://") + 1;
                    p_value_tmp1 = (char *)frmalloc(ui_value_len);
                    if(p_value_tmp1 == NULL)
                        goto ERROR;
                    snprintf(p_value_tmp1, ui_value_len, "http://%s", p_value);
                    frfree(p_value);
                    p_value = p_value_tmp1;
                    p_value_tmp1 = NULL;
                    frtrim(p_value);
                }

                //增加URI
                ui_value_len = strlen(p_uri) + strlen(p_value) + 1;
                p_value_tmp1 = (char *)frmalloc(ui_value_len);
                if(p_value_tmp1 == NULL)
                    goto ERROR;

                snprintf(p_value_tmp1, ui_value_len, "%s%s", p_value, p_uri);
                frfree(p_value);
                p_value = p_value_tmp1;
                p_value_tmp1 = NULL;
            }

            //title
            i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.url", p_value);
            if(i_ret == FR_FAIL)
            {
                frfree(p_field_name);
                frfree(p_value);
                return APM_L7_ANALYZE_FAIL;
            }

            //transaction.title
            p_value_tmp1 = strchr(p_value, '?');
            if(p_value_tmp1)
                *p_value_tmp1 = '\0';
            p_value_tmp1 = NULL;

            i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_value);
            if(i_ret == FR_FAIL)
            {
                frfree(p_field_name);
                frfree(p_value);
                return APM_L7_ANALYZE_FAIL;
            }

            frfree(p_field_name);
            frfree(p_value);
            p_field_name = NULL;
            p_value = NULL;
            continue;

        }
        else if(strcasecmp(p_field_name, "Authorization") == 0)
        {
            //
            i_ret = http_auth_parse(p_st_body_data, p_value, p_st_private);
            frfree(p_field_name);
            p_field_name = NULL;
            frfree(p_value);
            p_value = NULL;
            if(i_ret == FR_FAIL)
                return FR_FAIL;

            continue;
        }
        else if(strcasecmp(p_field_name, "Upgrade") == 0)
        {
            if(strcmp(p_value, "h2c") == 0)
                p_comm_session->i_upgrade = 1;
        }
        //存到结构体中
        frtrim(p_value);

        //字段名过滤
        i_ret = http_field_name_filter(p_field_name);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            p_field_name = NULL;
            p_value = NULL;
            continue;
        }

//        //content
//        if(strncmp(p_field_name, "content", 7) == 0)
//        {
//            if(p_st_private->i_flag_multipart)
//            {
//                frfree(p_field_name);
//                p_field_name = NULL;
//                frfree(p_value);
//                p_value = NULL;
//                continue;
//            }
//            //content-type.1
//            //p_field_name修改
//            ui_name_len = strlen(p_field_name) + strlen("request.http.header.") + 5;
//            p_field_name_tmp = frmalloc(ui_name_len);
//            if(p_field_name_tmp == NULL)
//                goto ERROR;
//
//            snprintf(p_field_name_tmp, ui_name_len, "request.http.header.%s.1", p_field_name);
//            frfree(p_field_name);
//            p_field_name = p_field_name_tmp;
//            p_field_name_tmp = NULL;
//        }

        //p_field_name修改
        ui_name_len = strlen(p_field_name) + strlen("request.http.header.") + 1;
        p_field_name_tmp = (char *)frmalloc(ui_name_len);
        if(p_field_name_tmp == NULL)
            goto ERROR;

        snprintf(p_field_name_tmp, ui_name_len, "request.http.header.%s", p_field_name);
        frfree(p_field_name);
        p_field_name = p_field_name_tmp;
        p_field_name_tmp = NULL;

        i_ret = frreport_body_l7_add_str(p_st_body_data, p_field_name, p_value);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_field_name);
        frfree(p_value);
        p_field_name = NULL;
        p_value = NULL;

    }

//    i_ret = frreport_body_l7_add_int(p_st_body_data, "request.http.multipart.size", 1);
//    if(i_ret == FR_FAIL)
//        return APM_L7_ANALYZE_FAIL;

    return APM_L7_ANALYZE_SUCC;

    ERROR:
    if(p_field_name_tmp)
        frfree(p_field_name_tmp);

    if(p_field_name)
        frfree(p_field_name);

    if(p_value_tmp1)
        frfree(p_value_tmp1);
    if(p_value_tmp2)
        frfree(p_value_tmp2);
    if(p_value)
        frfree(p_value);

    return APM_L7_ANALYZE_FAIL;
}


/*******************************************************************************
*  FUNC     :  req 数据获取
*  ARGS     :  p_tcp_body           (指向信息头)
*           :  ui_tcp_body_len       (信息长度)
*  RTN      :  APM_L7_ANALYZE_FAIL  (失败)
*           :  APM_L7_ANALYZE_TODO  (继续解析)
*           :  APM_L7_ANALYZE_SUCC  (成功)
*  NOTE     :
*******************************************************************************/
int http_get_whole_req_inf(L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, char *p_tcp_body, unsigned int ui_tcp_body_len)
{
    Frbyte_Packet *p_packet = NULL;
    char *p_header_buff = NULL;
    char *p_header_tmp = NULL;
    char *p_uri = NULL;
    char *p_tmp = NULL;
    int i_uri_len = 0;
    int i_ret = 0;
    int i_option = 0;
    unsigned int ui_pos_start = 0, ui_header_tmp_len = 0, ui_header_buff_len = 0;
    char *p_field_value = NULL;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_st_private == NULL || p_tcp_body == NULL || ui_tcp_body_len == 0 )
        return APM_L7_ANALYZE_FAIL;

    if(p_st_private->i_version == 1)
    {
        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
    }
    else if(p_st_private->i_version == 2)
    {
        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
    }

    //获取完整的请求体数据头
    p_packet = p_comm_session->p_st_data;
    if(p_packet == NULL)
    {
        p_comm_session->p_st_data = bytebuff_creat();
        p_packet = p_comm_session->p_st_data;
        if(p_packet == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if(p_http1_session->i_flag_req_finish == 0)
    {
        //如果  超过 HTTP_HEADER_MAX_SIZE 则认为丢包  不解析
        if(p_packet->ui_all_len > HTTP_HEADER_MAX_SIZE)
            return APM_L7_ANALYZE_FAIL;

        //判断 是否另起一个request
        if(p_packet->ui_all_len)
        {
            if(__http_req_header_detect(p_tcp_body, ui_tcp_body_len, NULL, NULL, &i_ret, NULL))
            {
                bytebuff_free(&p_comm_session->p_st_data);
                p_comm_session->p_st_data = bytebuff_creat();
                if(p_comm_session->p_st_data == NULL)
                    return APM_L7_ANALYZE_FAIL;
                
                p_packet = p_comm_session->p_st_data;
                p_comm_session->st_l4_trans.l_request_bytes = (long)ui_tcp_body_len;
                p_comm_session->st_l4_trans.st_request_time_first_byte.tv_sec = p_comm_session->st_l4_trans.st_request_time.tv_sec;
                p_comm_session->st_l4_trans.st_request_time_first_byte.tv_usec = p_comm_session->st_l4_trans.st_request_time.tv_usec;
            }
        }

        i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
        if(i_ret == FR_FAIL)
            goto ERROR;
        //p_header_buff \r\n\r\n
        if(bytebuff_memstr(p_packet, p_http1_session->i_start_pos, 0, "\r\n\r\n", strlen("\r\n\r\n"), (int *)&ui_header_buff_len) != FR_SUCC)
        {
            p_http1_session->i_start_pos = p_packet->ui_all_len - 4;
            if(p_http1_session->i_start_pos < 0)
                p_http1_session->i_start_pos = 0;

            return APM_L7_ANALYZE_TODO;
        }

        p_http1_session->i_start_pos = 0;
        ui_header_buff_len += 4;

        //取出第一行
        if(bytebuff_memstr(p_packet, 0, ui_header_buff_len, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), (int *)&ui_pos_start) != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        //指向下一行
        ui_pos_start += strlen(FR_HTTP_LINE_END);
        p_header_buff = (char *)frmalloc(ui_pos_start + 1);
        if(p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, ui_pos_start);
        if(i_ret == FR_FAIL)
            goto ERROR;
        p_header_buff[ui_pos_start] = '\0';
        //解析http请求体
        //开始行格式判断并指向字段开始行 当返回NULL不是http协议  该情况不存在
        p_header_tmp = __http_req_header_detect(p_header_buff, ui_pos_start, &p_uri, &i_uri_len, &i_option, p_st_body_data);
        if(p_header_tmp == NULL)
            goto ERROR;

        p_header_tmp = NULL;
        frfree(p_header_buff);
        p_header_buff = NULL;

        //get
        if(i_option == 1)
        {
            p_tmp = strchr(p_uri,'?');
            if(p_tmp == NULL)
            {
                p_field_value = NULL;
            }
            else
            {
                p_tmp++;
                p_field_value = frstrdup(p_tmp);
                frtrim(p_field_value);
            }

            //get  没有type字段
            if(p_field_value == NULL)
                i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.param.data", "\0");
            else
                i_ret = frreport_body_l7_add_str(p_st_body_data, "request.http.param.data", p_field_value);
            if(i_ret == FR_FAIL)
            {
                if(p_field_value)
                    frfree(p_field_value);
                return APM_L7_ANALYZE_FAIL;
            }
            if(p_field_value)
                frfree(p_field_value);

        }

        //获取字段并存入链表当中  直到读到单独空行为止
        p_comm_session->i_data_len = 0;
        i_ret = __http_get_req_inf(p_st_private, p_packet, p_st_body_data
                , p_uri, i_uri_len, &p_comm_session->i_data_len, i_option
                , ui_pos_start, ui_header_buff_len);

        if(i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        //释放p_uri
        if(p_uri)
        {
            frfree(p_uri);
            p_uri = NULL;
        }

        if(i_ret == APM_L7_ANALYZE_TODO)
            return APM_L7_ANALYZE_TODO;

        //request解析结束
        p_http1_session->i_flag_req_finish = 1;

        if(p_comm_session->i_data_len > 0)
        {
            //存req data
            ui_header_tmp_len = bytebuff_length(p_packet) - ui_header_buff_len;
            p_header_tmp = (char *)frmalloc(ui_header_tmp_len + 1);
            i_ret = bytebuff_get_bytes_at( p_packet, ui_header_buff_len, ui_header_tmp_len, p_header_tmp);
            if(i_ret == FR_FAIL)
                goto ERROR;
            p_header_tmp[ui_header_tmp_len] = '\0';

            bytebuff_free(&p_comm_session->p_st_data);
            i_ret = get_req_data(p_st_private, p_st_body_data, p_header_tmp, ui_header_tmp_len);
            frfree(p_header_tmp);
            p_header_tmp = NULL;
        }

        return i_ret;
    }
    
    i_ret = get_req_data(p_st_private, p_st_body_data, p_tcp_body, ui_tcp_body_len);

    return i_ret;

ERROR:
    if(p_uri)
        frfree(p_uri);

    if(p_header_buff)
        frfree(p_header_buff);

    if(p_header_tmp)
        frfree(p_header_tmp);

    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  取http响应头信息
*  ARGS     :  p_tcp_body           (指向体的头)
*           :  ui_tcp_body_len       (体的长度)
*  RTN      :  NULL                 (不是HTTP)
*           :  != NULL              (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC char* __http_resp_header_detect(char *p_tcp_body, unsigned int ui_tcp_body_len, L7session_http_private *p_st_private)
{
    char *p_pos = NULL, *p_http_info = NULL;
    char *p_response_codestring = NULL;
    long l_response_code = 0;
    char arr_tmp[4];
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_tcp_body == NULL || ui_tcp_body_len == 0)
        return NULL;

    if(p_st_private)
    {
        if(p_st_private->i_version == 1)
        {
            p_http1_session = p_st_private->p_http1_sess;
            p_comm_session = p_http1_session->p_st_comm_session;
        }
        else if(p_st_private->i_version == 2)
        {
            p_http2_session = p_st_private->p_http2_sess;
            p_comm_session = p_http2_session->p_st_comm_session;
        }
    }

    //比较http格式  HTTP/1*DIGIT.1*DIGIT (200 OK)\r\n

    p_http_info = p_tcp_body;
    if(strncasecmp(p_http_info,"HTTP/",5) != 0)
        return NULL;

    p_http_info += 5;

    p_pos = strchr(p_http_info,'.');
    if(p_pos == NULL || p_pos == p_http_info )
        return NULL;

    for(;p_http_info < p_pos;p_http_info++)
    {
        if(*p_http_info < '0' || *p_http_info > '9')
            return NULL;
    }

    p_http_info = p_pos+1;
    p_pos = strchr(p_http_info,' ');
    if(p_pos == NULL || p_pos == p_http_info )
        return NULL;

    for(;p_http_info < p_pos;p_http_info++)
    {
        if(*p_http_info < '0' || *p_http_info > '9')
            return NULL;
    }
    p_http_info = p_pos + 1;

    //判断状态码并存取
    if((p_http_info[0] >= '1' && p_http_info[0] <= '5')
       && (p_http_info[1] >= '0' && p_http_info[1] <= '9')
       && (p_http_info[2] >= '0' && p_http_info[2] <= '9')
       && (p_http_info[3] == ' '))
    {
        p_pos = strstr(p_http_info , FR_HTTP_LINE_END);
        if(p_pos == NULL)
            return NULL;
        //如果不需要取l_response_code p_response_codestring
        if(p_st_private == NULL)
            return p_pos + 2;

        memcpy(arr_tmp, p_http_info, 3);
        arr_tmp[3] = '\0';
        l_response_code = atoi(arr_tmp);
        if(p_comm_session->i_upgrade)
        {
            if(l_response_code != 101)
                p_comm_session->i_upgrade = 0;
        }

        p_comm_session->l_response_code = l_response_code;
        //取p_response_codestring
        if(p_pos - p_http_info - 4 > 0)
        {
            p_response_codestring = (char *)frmalloc(p_pos - p_http_info + 1);
            if(p_response_codestring == NULL)
                return NULL;
            snprintf(p_response_codestring, p_pos - p_http_info + 1, "%s", p_http_info);
            //frtrim(p_response_codestring);
            p_comm_session->p_code_string = p_response_codestring;

        }
        else if(((p_http_info[0] >= '2' && p_http_info[1] <= '0')
                 && (p_http_info[2] >= '0')))
        {
            p_response_codestring = (char *)frmalloc(2 + 1);
            if(p_response_codestring == NULL)
                return NULL;
            snprintf(p_response_codestring, 2 + 1, "OK");
            p_comm_session->p_code_string = p_response_codestring;
        }
        else
        {
            p_response_codestring = (char *)frmalloc(5 + 1);
            if(p_response_codestring == NULL)
                return NULL;
            snprintf(p_response_codestring, 5 + 1, "ERROR");
            p_comm_session->p_code_string = p_response_codestring;
        }

        return p_pos + 2;
    }

    return NULL;
}

int http1_get_resp_code(char *p_tcp_body, unsigned int ui_tcp_body_len, int *p_i_resp_code)
{
    char *p_pos = NULL, *p_http_info = NULL;
    int i_response_code = 0;
    char arr_tmp[4];
    
    if(p_tcp_body == NULL || ui_tcp_body_len < 16)
        return FR_FAIL;
    
    //比较http格式  HTTP/1*DIGIT.1*DIGIT (200 OK)\r\n
    
    p_http_info = p_tcp_body;
    if(strncasecmp(p_http_info,"HTTP/",5) != 0)
        return FR_FAIL;
    
    p_http_info += 5;
    
    p_pos = strchr(p_http_info,'.');
    if(p_pos == NULL || p_pos == p_http_info )
        return FR_FAIL;
    
    for(;p_http_info < p_pos;p_http_info++)
    {
        if(*p_http_info < '0' || *p_http_info > '9')
            return FR_FAIL;
    }
    
    p_http_info = p_pos+1;
    p_pos = strchr(p_http_info,' ');
    if(p_pos == NULL || p_pos == p_http_info )
        return FR_FAIL;
    
    for(;p_http_info < p_pos;p_http_info++)
    {
        if(*p_http_info < '0' || *p_http_info > '9')
            return FR_FAIL;
    }
    p_http_info = p_pos + 1;
    
    //判断状态码并存取
    if((p_http_info[0] >= '1' && p_http_info[0] <= '5')
       && (p_http_info[1] >= '0' && p_http_info[1] <= '9')
       && (p_http_info[2] >= '0' && p_http_info[2] <= '9')
       && (p_http_info[3] == ' '))
    {
        p_pos = strstr(p_http_info, FR_HTTP_LINE_END);
        if (p_pos == NULL)
            return FR_FAIL;
    
        memcpy(arr_tmp, p_http_info, 3);
        arr_tmp[3] = '\0';
        i_response_code = atoi(arr_tmp);
    }
        
    *p_i_resp_code = i_response_code;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  取http响应头信息中的字段，存入链表当中兵并跳过数据
*  ARGS     :  p_header_tmp             (指向信息体）
*           :  p_i_header_tmp_len       (信息长度)
*  RTN      :  0                        (成功)
*           :  APM_L7_ANALYZE_FAIL                        (失败)
*           :  APM_L7_ANALYZE_TODO                        (数据包格式错误 执行丢包操作)
*           :  APM_L7_ANALYZE_SUCC                        (解析结束）
*  NOTE     :
*******************************************************************************/
FR_STATIC int __http_get_resp_inf(Frbyte_Packet *p_packet, Frreport_body_data *p_st_body_data
        , int *p_i_data_len, L7session_http_private *p_st_private
        , int i_pos_start, int i_pos_end)
{
    char *p_value_tmp1 = NULL;
    char *p_value_tmp2 = NULL;
    char *p_value = NULL;
    unsigned int ui_name_len = 0, ui_value_len = 0;
    int i_pos = 0;
    int i_pos_tmp = i_pos_start;
    char tmp;
    int i_ret = 0;
    char *p_field_name = NULL, *p_field_name_tmp = NULL;
    char *p_boundary = NULL;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_packet == NULL || p_st_body_data == NULL || p_st_private == NULL
       || p_i_data_len == NULL || i_pos_start > i_pos_end || i_pos_start < 0)
        return APM_L7_ANALYZE_FAIL;

    if(p_st_private->i_version == 1)
    {
        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
    }
    else if(p_st_private->i_version == 2)
    {
        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
    }

    while(i_pos_tmp < i_pos_end - 4)
    {
        //p_header_inf内存申请

        //获取字段名
        if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, ":", 1, &i_pos) != FR_SUCC)
        {
            p_http1_session->i_flag_abandon = 1;
            return APM_L7_ANALYZE_FAIL;
        }

        ui_name_len = (unsigned int)i_pos - i_pos_tmp;
        //获取字段名并 ':'--> '\0'
        p_field_name = (char *)frmalloc(ui_name_len + 1);
        if(p_field_name == NULL)
            goto ERROR;
        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_name_len, p_field_name);
        if(i_ret == FR_FAIL)
            goto ERROR;
        p_field_name[ui_name_len] = '\0';
        frtrim(p_field_name);

        //转化为小写
        i_ret = frstrlower(p_field_name, ui_name_len);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            return APM_L7_ANALYZE_FAIL;
        }

        //指向：后一个字符
        i_pos_tmp = i_pos + 1;
        //获取value
        if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
            goto ERROR;

        ui_value_len = (unsigned int)i_pos - i_pos_tmp;
        p_value = (char *)frmalloc(ui_value_len + 1);
        if(p_value == NULL)
            goto ERROR;

        i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_value_len, p_value);
        if(i_ret == FR_FAIL)
            goto ERROR;
        p_value[ui_value_len] = '\0';
        frtrim(p_value);
        //p_header_tmp指向下一行
        i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);

        //如果下一行空格开头则前移
        bytebuffer_get_at(p_packet, i_pos_tmp, (uint8_t *)&tmp);
        while(tmp == ' ' || tmp == '\t')
        {
            //跳过空格
            i_pos_tmp++;
            if(bytebuff_memstr(p_packet, i_pos_tmp, i_pos_end, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos) != FR_SUCC)
                goto ERROR;

            ui_value_len = (unsigned int)i_pos - i_pos_tmp;
            p_value_tmp1 = (char *)frmalloc(ui_value_len + 1);
            if(p_value_tmp1 == NULL)
                goto ERROR;
            i_ret = bytebuff_get_bytes_at(p_packet, i_pos_tmp, ui_value_len, p_value_tmp1);
            if(i_ret == FR_FAIL)
                goto ERROR;
            p_value_tmp1[ui_value_len] = '\0';
            frtrim(p_value_tmp1);
            //合并
            ui_value_len = strlen(p_value) + strlen(p_value_tmp1);
            p_value_tmp2 = (char *)frmalloc(ui_value_len + 1);
            if(p_value_tmp2 == NULL)
                goto ERROR;

            snprintf(p_value_tmp2, ui_value_len, "%s%s", p_value, p_value_tmp1);
            frfree(p_value);
            frfree(p_value_tmp1);
            p_value_tmp1 = NULL;
            p_value = p_value_tmp2;
            p_value_tmp2 = NULL;
            //p_header_tmp指向下一行
            i_pos_tmp = i_pos + strlen(FR_HTTP_LINE_END);
            bytebuffer_get_at(p_packet, i_pos_tmp, (uint8_t *)&tmp);
        }

        frtrim(p_value);
        //如果是Content-Length，则存下Content-Length
        if(strcasecmp(p_field_name, "Content-Length") == 0)
        {
            *p_i_data_len = atoi(p_value);
        }
            //判断Content-Type
        else if(strcasecmp(p_field_name, "Content-Type") == 0)
        {
            //获取charset
            p_value_tmp1 = strstr(p_value, "charset=");
            if(p_value_tmp1 == NULL)
            {
                snprintf(p_comm_session->arr_charset, sizeof(p_comm_session->arr_charset), "%s", "utf-8");
            }
            else
            {
                //指向内容
                p_value_tmp1 += 8;
                snprintf(p_comm_session->arr_charset, sizeof(p_comm_session->arr_charset), "%s", p_value_tmp1);
                p_value_tmp1 = strchr(p_comm_session->arr_charset, ';');
                if(p_value_tmp1)
                    *p_value_tmp1 = '\0';

                frtrim(p_comm_session->arr_charset);
            }

            http_data_type_detect(p_value,p_comm_session);

            //p_boundary
            p_value_tmp1 = strstr(p_value, "boundary=");
            if(p_value_tmp1)
            {
                //boundary
                p_comm_session->i_flag_multipart = 1;

                //指向=之后 获取boundary
                p_value_tmp1 += 9;
                p_value_tmp2 = strchr(p_value_tmp1, ';');
                if(p_value_tmp2 == NULL)
                    ui_value_len = strlen (p_value_tmp1) + 1;
                else
                    ui_value_len = p_value_tmp2 - p_value_tmp1 + 1;

                p_boundary = (char *)frmalloc(ui_value_len);
                if(p_boundary == NULL)
                {
                    p_value_tmp1 = NULL;
                    p_value_tmp2 = NULL;
                    goto ERROR;
                }
                snprintf(p_boundary, ui_value_len, "%s", p_value_tmp1);
                p_value_tmp1 = NULL;
                p_value_tmp2 = NULL;

                //获取boundary 不上报此字段
                if(p_comm_session->p_boundary)
                    frfree(p_comm_session->p_boundary);
                p_comm_session->p_boundary = p_boundary;
                p_boundary = NULL;

            }
        }
        else if(strcasecmp(p_field_name, "Content-Encoding") == 0)
        {
            if(strncasecmp(p_value, "gzip", 4) == 0)
                p_comm_session->i_flag_gzip = 1;
            if(strncasecmp(p_value, "deflate", 7) == 0)
                p_comm_session->i_flag_deflate = 1;
        }
        else if(strcasecmp(p_field_name, "Transfer-Encoding") == 0)
        {
            if(strncasecmp(p_value, "chunked", 7) == 0)
                p_comm_session->i_flag_chunk = 1;
        }

        //字段名过滤
        i_ret = http_field_name_filter(p_field_name);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            p_field_name = NULL;
            p_value = NULL;
            continue;
        }

        //p_field_name修改
        ui_name_len = strlen(p_field_name) + strlen("response.http.header.") + 1;
        p_field_name_tmp = (char *)frmalloc(ui_name_len);
        if(p_field_name_tmp == NULL)
            goto ERROR;

        snprintf(p_field_name_tmp, ui_name_len, "response.http.header.%s", p_field_name);
        frfree(p_field_name);
        p_field_name = p_field_name_tmp;
        p_field_name_tmp = NULL;


        //存到结构体中
        i_ret = frreport_body_l7_add_str(p_st_body_data, p_field_name, p_value);
        if(i_ret == FR_FAIL)
        {
            frfree(p_field_name);
            frfree(p_value);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_field_name);
        frfree(p_value);
        p_field_name = NULL;
        p_value = NULL;

    }

//    i_ret = frreport_body_l7_add_int(p_st_body_data, "response.http.multipart.size", 1);
//    if(i_ret == FR_FAIL)
//        return APM_L7_ANALYZE_FAIL;

    return APM_L7_ANALYZE_SUCC;

ERROR:
    if(p_field_name)
        frfree (p_field_name);

    if(p_value)
        frfree(p_value);
    if(p_value_tmp1)
        frfree(p_value_tmp1);
    if(p_value_tmp2)
        frfree(p_value_tmp2);

    return APM_L7_ANALYZE_FAIL;
}



/*******************************************************************************
*  FUNC     :  获取完整的请求体并解析
*  ARGS     :  p_header_tmp         (指向信息头)
*           :  p_i_header_tmp_len   (信息长度)
*  RTN      :  APM_L7_ANALYZE_FAIL                    (失败)
*           :  APM_L7_ANALYZE_TODO                    (数据包未结束)
*           :  APM_L7_ANALYZE_SUCC                    (解析结束）
*  NOTE     :
*******************************************************************************/
int http_get_whole_resp_inf(L7session_http_private *p_st_private, Frreport_body_data *p_st_body_data, char *p_tcp_body, unsigned int ui_tcp_body_len)
{
    Frbyte_Packet *p_packet = NULL;
    char *p_header_tmp = NULL;
    unsigned int ui_header_tmp_len = 0, ui_header_buff_len = 0;
    int i_ret = 0;
    char *p_header_buff = NULL;
    int i_pos_start = 0;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;

    if(p_st_private == NULL || p_tcp_body == NULL || ui_tcp_body_len == 0)
        return APM_L7_ANALYZE_FAIL;

    if(p_st_private->i_version == 1)
    {
        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
    }
    else if(p_st_private->i_version == 2)
    {
        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
    }
    
    //获取字段并存入链表当中
    if(p_http1_session->i_flag_resp_finish == 0)
    {
        //获取完整的请求体数据头
        p_packet = p_comm_session->p_st_data;
        if(p_packet == NULL)
        {
            p_comm_session->p_st_data = bytebuff_creat();
            p_packet = p_comm_session->p_st_data;
            if(p_packet == NULL)
                return APM_L7_ANALYZE_FAIL;
        }

        //如果  超过 HTTP_HEADER_MAX_SIZE 则认为丢包  不解析
        if(p_packet->ui_all_len > HTTP_HEADER_MAX_SIZE)
            return APM_L7_ANALYZE_FAIL;

        //判断 是否另起一个request
        if(p_packet->ui_all_len)
        {
            if(__http_resp_header_detect(p_tcp_body, ui_tcp_body_len, NULL))
            {
                bytebuff_free(&p_comm_session->p_st_data);
                p_comm_session->p_st_data = bytebuff_creat();
                if(p_comm_session->p_st_data == NULL)
                    return APM_L7_ANALYZE_FAIL;
    
                p_packet = p_comm_session->p_st_data;
                p_comm_session->st_l4_trans.l_request_bytes = (long)ui_tcp_body_len;
                p_comm_session->st_l4_trans.st_response_time_first_byte.tv_sec = p_comm_session->st_l4_trans.st_response_time.tv_sec;
                p_comm_session->st_l4_trans.st_response_time_first_byte.tv_usec = p_comm_session->st_l4_trans.st_response_time.tv_usec;
            }
        }

        i_ret = bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
        if(i_ret == FR_FAIL)
            goto ERROR;

        //\r\n\r\n
        if(bytebuff_memstr(p_packet, p_http1_session->i_start_pos, 0, "\r\n\r\n", strlen("\r\n\r\n"), (int *)&ui_header_buff_len) != FR_SUCC)
        {
            p_http1_session->i_start_pos = p_packet->ui_all_len - 4;
            if(p_http1_session->i_start_pos < 0)
                p_http1_session->i_start_pos = 0;

            return APM_L7_ANALYZE_TODO;
        }

        p_http1_session->i_start_pos = 0;
        ui_header_buff_len += 4;

        //取出第一行
        if(bytebuff_memstr(p_packet, 0, ui_header_buff_len, FR_HTTP_LINE_END, strlen(FR_HTTP_LINE_END), &i_pos_start) != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        //指向下一行
        i_pos_start += strlen(FR_HTTP_LINE_END);
        p_header_buff = (char *)frmalloc((unsigned int)i_pos_start + 1);
        if(p_header_buff == NULL)
            return APM_L7_ANALYZE_FAIL;

        i_ret = bytebuff_peek_bytes(p_packet, p_header_buff, (unsigned int)i_pos_start);
        if(i_ret == FR_FAIL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        p_header_buff[i_pos_start] = '\0';
        //解析http请求体
        //开始行格式判断并指向字段开始行 当返回NULL不是http协议  该情况不存在
        p_header_tmp = __http_resp_header_detect(p_header_buff, (unsigned int)i_pos_start, p_st_private);
        if(p_header_tmp == NULL)
        {
            frfree(p_header_buff);
            return APM_L7_ANALYZE_FAIL;
        }
        frfree(p_header_buff);
        p_header_buff = NULL;
        p_header_tmp = NULL;

        //跳过\r\n
        ui_header_tmp_len = (unsigned int)i_pos_start;

        //解析头信息
        p_comm_session->i_data_len = 0;
        i_ret = __http_get_resp_inf(p_packet, p_st_body_data, &p_comm_session->i_data_len, p_st_private, ui_header_tmp_len, ui_header_buff_len);
        if(i_ret == APM_L7_ANALYZE_FAIL)
            return i_ret;

        //刚好解析完成
        if(i_ret == APM_L7_ANALYZE_SUCC)
        {
            p_http1_session->i_flag_resp_finish = 1;
            //存取响应数据
            if(p_comm_session->i_flag_chunk == 0 && p_comm_session->i_data_len == 0)
                return APM_L7_ANALYZE_SUCC;

            //存取resp data
            ui_header_tmp_len = (bytebuff_length(p_packet) - ui_header_buff_len);
            p_header_tmp = (char *)frmalloc(ui_header_tmp_len + 1);
            if(p_header_tmp == NULL)
                goto ERROR;
            i_ret = bytebuff_get_bytes_at(p_packet, ui_header_buff_len, ui_header_tmp_len, p_header_tmp);
            if(i_ret == FR_FAIL)
                goto ERROR;
            p_header_tmp[ui_header_tmp_len] = '\0';
            bytebuff_free(&p_comm_session->p_st_data);
            i_ret = get_resp_data(p_st_private, p_st_body_data, p_header_tmp,ui_header_tmp_len);
            frfree(p_header_tmp);
            p_header_tmp = NULL;
            return i_ret;

        }
        //解析出错
        if(i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;
    }
    else
    {
        //存取响应数据或者丢包   纯数据
        i_ret = get_resp_data(p_st_private, p_st_body_data, p_tcp_body,ui_tcp_body_len);
        return i_ret;
    }

ERROR:
    if(p_header_tmp)
        frfree(p_header_tmp);

    if(p_packet)
        bytebuff_free(&p_comm_session->p_st_data);

    return APM_L7_ANALYZE_FAIL;
}


/*******************************************************************************
*  FUNC     :  判断是否是TCP协议
*  ARGS     :  p_st_conn                    输入数据信息
*           :  p_st_packet                 输入数据
*  RTN      :  APM_L7_IS_NO                 不属于TCP协议
*           :  APM_L7_IS_YES                属于TCP协议
*  NOTE     :
*******************************************************************************/
int http1_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_header_tmp = NULL;
    int i_option = 0, i_ret_fun=0;

    if(p_st_packet == NULL || p_st_conn==NULL)
        return APM_L7_IS_NO;

    //判断是否属于http request
    p_header_tmp = __http_req_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len, NULL, NULL,&i_option, NULL);
    if(p_header_tmp)
    {
        i_ret_fun = frct_get_direct_known(p_st_conn);
        if( i_ret_fun == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);

//        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
        return APM_L7_IS_YES;
    }

    //判断是否属于http response
    p_header_tmp = __http_resp_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len,NULL);
    if(p_header_tmp)
    {
        i_ret_fun = frct_get_direct_known(p_st_conn);
        if( i_ret_fun == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);

//        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
        return APM_L7_IS_YES;
    }

    return APM_L7_IS_NO;
}


